# -*- coding: utf-8 -*-
# created on 2016/5/5

from mathsolver.functions.base import *
from sympy.abc import x, y
from sympy import pi, atan, solve, Tuple, solveset


def default_symbols(expr, args=None):
    if args is None:
        args = []
    if len(args) > 1:
        return args[1].sympify()
    elif (x in expr.free_symbols) or (y in expr.free_symbols):
        return x, y
    else:
        return expr.free_symbols.pop()


def point_to_line_dis2(point, line):
    point = point.sympify()
    yibanxingshi = ZhiXian(line).yibanshi.sympify()
    a, b, c = ZhiXian(line).get_coeff()
    a = a.sympify()
    b = b.sympify()
    return yibanxingshi[0].subs({x: point[0], y: point[1]}) ** 2 / (a ** 2 + b ** 2)


def zl_search_multiple(known, poly):  # todo: one key save all values !
    symbols = poly.free_symbols
    symbols = list(symbols)
    symbols = set(symbols)
    answer = []
    for name in known:
        if isinstance(name, Tuple):
            new_name = set(name)
            if new_name & symbols <= new_name:
                values = known[name]
                for value in values:
                    type_flag = []
                    for sym, v in zip(name, value):
                        if isinstance(v, Interval):
                            type_flag.append(1)
                        else:
                            type_flag.append(0)
                    if sum(type_flag) == 0:
                        symbol_value = dict([(sym, v) for sym, v in zip(name, value)])
                        answer.append(symbol_value)
                    else:
                        for sym, v in zip(name, value):
                            if not isinstance(v, Interval):
                                answer.append({sym: v})
        else:
            if name in symbols:
                # value = list(known[name])
                value = list(known[name])[0]
                symbol_value = {name: value}
                answer.append(symbol_value)
    return answer


class ZhiXian(object):
    def __init__(self, eq):
        self.eq = eq.sympify()
        self.yibanshi = self.get_yibanshi()
        self.A, self.B, self.C = self.get_coeff()
        self.direction_Vector = self.get_direction_vector()
        self.normal_Vector = self.get_normal_vector()
        self.slope = self.get_slope()
        if not self.slope.sympify().free_symbols:
            self.qingxiejiao = self.get_qingxiejiao()
        self.xOffset, self.yOffset = self.get_offset()
        self.AxisPoints = self.get_axis_points()
        if self.A.sympify() != 0 and self.B.sympify() != 0:
            self.jiejushi = self.get_jiejushi()

    def get_yibanshi(self):
        eq = self.eq
        expr = (eq[0] - eq[1]).expand()
        xx = Symbol("x")
        yy = Symbol("y")
        coeff_x = expr.coeff(xx)
        coeff_y = expr.coeff(yy)

        f = coeff_x * xx + coeff_y * yy
        rest = (expr - f).simplify()
        return BaseZhiXian({"name": "", "value": [f + rest, S.Zero]})

    def get_coeff(self):
        yibanshi = self.get_yibanshi().sympify()
        expr = yibanshi[0]
        symx, symy = default_symbols(expr)
        a = yibanshi[0].coeff(symx)
        b = yibanshi[0].coeff(symy)
        c = (yibanshi[0] - a * symx - b * symy).expand().simplify()
        return BaseValue(a), BaseValue(b), BaseValue(c)

    def get_direction_vector(self):
        a = self.A.sympify()
        b = self.B.sympify()
        return BaseVector({"name": "", "value": [-b, a]})

    def get_normal_vector(self):
        a = self.A.sympify()
        b = self.B.sympify()
        return BaseVector({"name": "", "value": [a, b]})

    def get_slope(self):
        a = self.A.sympify()
        b = self.B.sympify()
        if b == 0:
            slope = S.Infinity
        else:
            slope = - a / b
        return BaseValue(slope)

    def get_qingxiejiao(self):
        b = self.B.sympify()
        if b == 0:
            qingxiejiao = pi / 2
        else:
            slope = self.slope.sympify()
            if slope >= 0:
                qingxiejiao = atan(slope)
            else:
                qingxiejiao = pi + atan(slope)
        return BaseValue(qingxiejiao)

    def get_offset(self):
        yibanshi = self.get_yibanshi().sympify()
        f = yibanshi[0]
        symx, symy = default_symbols(f)
        if f.has(symx) and not f.has(symy):
            x_offset = solve(f, symx)[0]
            y_offset = None
        elif not f.has(symx) and f.has(symy):
            x_offset = None
            y_offset = solve(f, symy)[0]
        else:
            symx, symy = default_symbols(f)
            new_fx = f.subs({symy: S.Zero})
            new_fy = f.subs({symx: S.Zero})
            x_answer = solve(new_fx, symx)
            y_answer = solve(new_fy, symy)
            x_offset = x_answer[0]
            y_offset = y_answer[0]
        return BaseValue(x_offset), BaseValue(y_offset)

    def get_axis_points(self):
        x_offset = self.xOffset.sympify()
        y_offset = self.yOffset.sympify()
        return BasePoints([{"name": "x轴", "value": [x_offset, S.Zero]}, {"name": "y轴", "value": [S.Zero, y_offset]}])

    def get_jiejushi(self):
        yibanshi = self.yibanshi.sympify()
        expr = yibanshi[0]
        symx, symy = default_symbols(expr)
        jies = solveset(expr, symy)
        right = jies.args[0]
        return BaseZhiXian({"name": "", "value": [symy, right]})


if __name__ == '__main__':
    pass
